/*******************************************************************************
 * This file is part of blueprint4j www.blueprint4j.org.
 * 
 *     blueprint4j is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     blueprint4j is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with blueprint4j. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package blueprint4j.db;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.Date;

import blueprint4j.utils.Log;
import blueprint4j.utils.Settings;
import blueprint4j.utils.Utils;
import blueprint4j.utils.VectorInteger;
import blueprint4j.utils.VectorString;

public abstract class DataBaseUtils {

	 public abstract SimpleDateFormat getDateTimeFormat();
	 public abstract SimpleDateFormat getTimeFormat();
	 public abstract SimpleDateFormat getDateFormat();

	 public static final String DB_IP_NAME = "database.ip",
				DB_USER_NAME = "database.username",
				DB_PASS_NAME = "database.password";

	 public static final String DB_IP = Settings.getString(DB_IP_NAME,"localhost"),
				DB_USER = Settings.getString(DB_USER_NAME,"root"),
				DB_PASS = Settings.getString(DB_PASS_NAME,"");

	 /**
	  * Do Insert and readback
	  */
	 abstract public Long getNextIndexField(Entity entity) throws SQLException;

	 /**
	  * Sets AutoId Field's value before insertion occurrs
	  */
	 public void setBeforeInsert(DBConnection connection,FieldAutoId id) throws SQLException {}

	 /**
	  * Load id from auto increment field
	  */
	 abstract void loadIdAfterInsert(DBConnection connection,FieldId id) throws SQLException;

	 /**
	  * Create Index Table
	  */
	 abstract public void createIndexTable(Statement st) throws SQLException;

	 /**
	  * Convert a Time to SQL
	  *
	  * @param date the DateTime to be converted
	  * @return a string copy of the date ready to by used in the SQL including ' characters
	  */
	 abstract public String convertTimeToSQLString(Date date);

	 abstract public String castTime(String date);

	 public String castTime(Date date) {
		  return "cast("+convertTimeToSQLString(date)+" AS TIME)";
	 }

	 public String castTimeForField(String field) {
		  return "cast(" +field+" AS TIME)";
	 }

	 /**
	  * Convert a Date to SQL leave out the time
	  *
	  * @param date the Date to be converted
	  * @return a string copy of the date ready to by used in the SQL including ' characters
	  */
	 abstract public String convertDateToSQLString(Date date);

	 /**
	  * The SQL statement to retrieve the current date value
	  *
	  * @return the sql statement used to retrieve the current date value without time
	  */
	 abstract public String currentDateSQLMethod();

	 /**
	  * Convert a Date to SQL including time
	  *
	  * @param date the DateTime to be converted
	  * @return a string copy of the date ready to by used in the SQL including ' characters
	  */
	 abstract public String convertDateTimeToSQLString(Date date);

	 /**
	  * The SQL statement to retrieve the current date value
	  *
	  * @return the sql statement used to retrieve the current date value with time
	  */
	 abstract public String currentDateTimeSQLMethod();

	 /**
	  * Get the SQL command for top or first
	  *
	  * @param number The number of rows you would like back from the select.
	  * @return Returns the SQL string command to limit the number of rows returned in a system
	  */
	 abstract public String sqlFirstString(String sql,int number);

	 /**
	  * Converts a string value to a suitable value for an SQL statement
	  *
	  * @param source The value of the string
	  * @return A converted string ready for use in SQL
	  */
	 abstract public String convertStringForSQL(String source);

	 /**
	  * Converts a string after is has been returned from the database
	  *
	  * @param source The value of the string from the database
	  * @return A converted string converted from the SQL syntax
	  */
	 abstract public String convertStringFromSQL(String source);

	 abstract String dateSUB_HOUR(Date date,int hours);

	 abstract String dateSUB_MIN(Date date,int min);

	 abstract String dateSUB_SEC(Date date,int sec);

	 abstract boolean mayUpdateFromResultSet(DBConnection dbcon) throws SQLException;

	 public String convertTabnameToLocal(String tabnmame) {
		  return tabnmame;
	 }

	 /**
	  * Replace all instances of each string pair
	  *
	  * @param source The source string to replace parts from
	  * @param pairs The value pairs to replace
	  * @return The new converted string
	  */
	 public String replaceParts(String source,String[][] parts){
		  StringBuffer out=new StringBuffer();
		  byte[] bytes=source.getBytes();
		  for (int t=0;t<source.length();t++){
				// Does this starting position match any of our source pairs
				for (int u=0;u<parts.length;u++){
					 // Possible match?
					 if (bytes[t]==parts[u][0].charAt(0)){
						  boolean match=true;
						  for (int p=1;p<parts[u][0].length() && match && p+t<bytes.length;p++){
								match&=(bytes[t+p]==parts[u][0].charAt(p));
						  }
						  // Replace and move to end
						  if (match){
								out.append(parts[u][1]);
								t+=parts[u][0].length()-1;
								break;
						  }
					 }
				}
				// Add next character to out.
				out.append(bytes[t]);
		  }
		  return out.toString();
	 }

	 public static String replaceAll(String source, String find_str, String replace_str) {
		  String buffer = "";
		  while (source.indexOf(find_str) != -1) {
				buffer = buffer + source.substring(0, source.indexOf(find_str)) + replace_str;
				source = source.substring(source.indexOf(find_str) + find_str.length());
		  }
		  return buffer + source;
	 }

	 abstract void executeKeepAliveSQL(DBConnection dbcon) throws SQLException;

	 abstract void executeOptimizeTable(DBConnection dbcon,String table_name) throws SQLException;

	 public String getCreateIndexSQL(Index index)
	 throws DataException {
		  if (index instanceof Index.UniqueIndex) {
				return "create unique index "+ index.index_name + " on " + index.table_name +"(" +index.fields.toString(",")+")";
		  } else {
				return "create index "+ index.index_name + " on " + index.table_name +"(" +index.fields.toString(",")+")";
		  }
	 }

	 abstract void dropIndex(DBConnection connection,String table_name,String index_name) throws SQLException,DataException;

	 protected void createTableVersion(DBConnection dbcon) throws SQLException {
		  dbcon.execute("create table " + TableVersion.TABLE_NAME + "( " +
					 "name varchar(250),version bigint"+
					 ")"
					 );
	 }

	 protected void createTable(DBConnection connection,String create_syntax,Entity entity,VectorField table_fields)
	 throws SQLException {
		  String create_sql = create_syntax + " "+ entity.getTableName() + "( ";
		  for (int i =0;i < table_fields.size();i++) {
				create_sql += table_fields.get(i).getName() + " " + getSQLType(table_fields.get(i)) + ",";
		  }
		  create_sql = create_sql.substring(0,create_sql.length()-1);
		  create_sql += ")";
		  Log.sql.out("Updating Database",create_sql);
		  try {
				connection.execute(create_sql);
		  } catch (SQLException sqle) {
				if (sqle.getMessage().indexOf("already exists")==-1) {
					 throw sqle;
				} else {
					 Log.debug.out(sqle);
				}
		  }
	 }

	 public void createTable(DBConnection connection,Entity entity,VectorField table_fields)
	 throws SQLException {
		  createTable(connection,"create table",entity,table_fields);
	 }

	 public void createTemporaryTable(DBConnection connection,Entity entity,VectorField table_fields)
	 throws SQLException {
		  createTable(connection,"create temporary table",entity,table_fields);
	 }

	 private void getTableMetaData(DBConnection connection,String table_name,VectorString databasenames,VectorInteger databasesize,VectorInteger databasetype)
	 throws Exception {
		  Statement statement = connection.createStatement();
		  ResultSetMetaData metadata = statement.executeQuery(sqlFirstString("select * from " + table_name,1)).getMetaData();
		  databasenames.clear();
		  databasesize.clear();
		  databasetype.clear();
		  for (int i = 1;i <= metadata.getColumnCount();i++) {
				databasenames.add(metadata.getColumnName(i));
				databasesize.add(new Integer(metadata.getColumnDisplaySize(i)));
				databasetype.add(new Integer(metadata.getColumnType(i)));
		  }
		  statement.close();
	 }

	 public boolean mayUpdate(DBConnection connection,String table_name)
	 throws Exception {
		  if (connection.hasTableBeenUpdated(table_name)) {
				return false;
		  }
		  return true;
	 }

	 public void updateEntity(
				DBConnection connection,
				Entity entity,
				boolean forceupdate
				) {
		  try {
				String table_name = entity.getTableName();
				VectorField table_fields = entity.getFields();
				Index.VectorIndex index = entity.getIndexes();
				FieldRename.VectorFieldRename rename_field = entity.getRenameField();

				// SETUP DATABASE SERVER - MIGHT ONLY BE DONE FOR SERVER
								/*
								if (Settings.getBoolean("database.init.setup",true)) {
										  synchronized (database_setup) {
													 if (!database_setup.booleanValue()) {
																database_setup = new Boolean(true);
																setupDatabaseServer(connection);
													 }
										  }
								}*/
				if (!connection.getTables().containsIgnoreCase(table_name)) {
					 createTable(connection,entity,table_fields);
					 connection.addTable(table_name);
				}
				// MAKE SURE THAT THE TABLE VERSION IS COMPATIBLE WITH THE SOFTWARE

				long table_version = TableVersion.getTableVersion(connection,table_name);
				long entity_version = Utils.getClassModifiedTime(entity.getClass());
				if (entity_version < table_version) {
					 //if (!Utils.isLexGreaterEqualsThan(version,table_version)) {
					 Log.critical.out(new Exception("THE ENTITY ["+table_name+"] VERSION ["+new Date(entity_version)+"] IS NOT COMPATIBLE WITH DATABASE WHICH IS A NEWER RELEASE["+new Date(table_version)+"]"));
				} else if (entity_version == table_version && !forceupdate) {
					 return;
				}
				// make sure that table exists
				VectorString databasenames = new VectorString();
				VectorInteger databasesize = new VectorInteger();
				VectorInteger databasetype = new VectorInteger();
				getTableMetaData(connection,table_name,databasenames,databasesize,databasetype);
				VectorString fieldnames = new VectorString();
				VectorInteger fieldsize = new VectorInteger();
				for (int i = 0;i < table_fields.size();i++) {
					 fieldnames.add(table_fields.get(i).getName());
					 fieldsize.add(new Integer(table_fields.get(i).getLength()));
				}
				// CHANGE NAMES OF FIELDS THAT HAVE CHANGED
				for (int i = 0;i < rename_field.size();i++) {
					 if (
								!databasenames.containsIgnoreCase(rename_field.get(i).field.getName()) &&
								databasenames.containsIgnoreCase(rename_field.get(i).old_name)
								) {
						  Log.sql.out(
									 "Updating Database",
									 "change name from ["+
									 rename_field.get(i).old_name+"] TO ["+
									 rename_field.get(i).field.getName()+"]"
									 );
						  modifyTableField(connection,rename_field.get(i).old_name,rename_field.get(i).field);
						  databasenames.remove(rename_field.get(i).old_name);
						  databasenames.add(rename_field.get(i).field.getName());
					 }
				}
				// remove fields that are not there
				for (int i = 0;i < databasenames.size();i++) {
					 if (!fieldnames.containsIgnoreCase(databasenames.get(i))) {
						  Log.trace.out("Updating Database",getDropField(databasenames.get(i),table_name));
						  connection.execute(getDropField(databasenames.get(i),table_name));
					 }
				}
				// create new fields
				for (int i = 0;i < fieldnames.size();i++) {
					 if (!databasenames.containsIgnoreCase(fieldnames.get(i))) {
						  addField(connection,table_fields.get(i));
					 }
				}
				getTableMetaData(connection,table_name,databasenames,databasesize,databasetype);
				// make sure that all fields are of the correct type
				for (int i = 0;i < table_fields.size();i++) {
					 int type = databasetype.get(databasenames.indexOfIgnoreCase(fieldnames.get(i))).intValue();
					 int size = databasesize.get(databasenames.indexOfIgnoreCase(fieldnames.get(i))).intValue();
					 if (isCorrectType(table_fields.get(i),type,size) != null && !isCorrectType(table_fields.get(i),type,size).booleanValue()) {
						  Log.trace.out("Updating Database","Incorrect Type " + table_fields.get(i).getName() + " " + type + " " + size);
						  modifyTableField(connection,table_fields.get(i));
					 }
				}
				// now update Table Version
				//if (Utils.isLexGreaterThan(version,table_version)) {
				if (entity_version > table_version) {
					 //if (version.compareTo(table_version) > 0) {
					 TableVersion.updateTableVersion(connection,table_name,entity_version);
				}
				// UPDATE TABLE INDEXES
				index.updateIndex(connection.getIndexes(),connection);
				index.dropExtraIndexes(connection,connection.getIndexes(),table_name);
		  } catch (Throwable exception) {
				Log.critical.out(exception);
		  }
	 }

	 protected Boolean isCorrectType(Field field,int type,int size)
	 throws DataException {
		  if (field instanceof FieldBigInteger) {
				if (type == Types.BIGINT) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] BIGINTEGER MISMATCH GOT ["+type+"] EXPECTING ["+Types.BIGINT+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldBigDecimal) {
				if (type == Types.DOUBLE) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] BIGIDECIMAL MISMATCH GOT ["+type+"] EXPECTING ["+Types.DOUBLE+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldBoolean) {
				if ((type == Types.CHAR || type == Types.VARCHAR) && size == 1) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] BOOLEAN MISMATCH GOT ["+type+"] EXPECTING ["+Types.CHAR+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldCharacter) {
				if  ((type == Types.CHAR || type == Types.VARCHAR) && size == 1) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] CHAR MISMATCH GOT ["+type+"] EXPECTING ["+Types.CHAR+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldColor) {
				if ((type == Types.CHAR || type == Types.VARCHAR) && size == 6) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] VARCHAR MISMATCH GOT ["+type+"] EXPECTING ["+Types.CHAR+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldCurrency) {
//				if (type == Types.FLOAT || type == Types.DOUBLE || type == Types.REAL || type == Types.DECIMAL) {
				if (type == Types.DECIMAL) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] DECIMAL MISMATCH GOT ["+type+"] EXPECTING ["+Types.DECIMAL+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldDate) {
				if (type == Types.DATE) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] DATE MISMATCH GOT ["+type+"] EXPECTING ["+Types.DATE+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldDateTime) {
				if (type == Types.TIMESTAMP) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] TIMESTAMP MISMATCH GOT ["+type+"] EXPECTING ["+Types.TIMESTAMP+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldDouble) {
				if (type == Types.DOUBLE) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] DOUBLE MISMATCH GOT ["+type+"] EXPECTING ["+Types.DOUBLE+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldInteger) {
				if (type == Types.INTEGER){
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] INTEGER MISMATCH GOT ["+type+"] EXPECTING ["+Types.INTEGER+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldLong) {
				if (type == Types.BIGINT) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] LONG MISMATCH GOT ["+type+"] EXPECTING ["+Types.BIGINT+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldString) {
				if ((type == Types.VARCHAR || type == Types.CHAR)  && size == ((FieldString)field).getLength()) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] VARCHAR MISMATCH GOT ["+type+"] EXPECTING ["+Types.VARCHAR+"] SIZE ["+size+"] ["+((FieldString)field).getLength()+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldTime) {
				if (type == Types.TIME) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] TIME MISMATCH GOT ["+type+"] EXPECTING ["+Types.TIME+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldText) {
				if (type == Types.LONGVARCHAR || type == Types.VARCHAR) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] TEXT MISMATCH GOT ["+type+"] EXPECTING ["+Types.LONGVARCHAR+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldBlob) {
				if (type == Types.BLOB || type == Types.LONGVARBINARY) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] BLOB MISMATCH GOT ["+type+"] EXPECTING ["+Types.BLOB+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldImage) {
				if (type == Types.LONGVARBINARY) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] IMAGE MISMATCH GOT ["+type+"] EXPECTING ["+Types.LONGVARBINARY+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldProperties) {
				if (type == Types.LONGVARCHAR || type == Types.VARCHAR) {
					 return new Boolean(true);
				} else {
					 Log.trace.out("Updating Database","FIELD ["+field.getName()+"] ["+field.getEntity().getTableName()+"] LONGVARCHAR MISMATCH GOT ["+type+"] EXPECTING ["+Types.LONGVARCHAR+"]");
					 return new Boolean(false);
				}
		  }
		  if (field instanceof FieldCombiner) {
				return null;
		  }
		  throw new DataException("FIELD TYPE NOT FOUND " + field + " " +field.getClass());
	 }

	 public String getSQLType(Field field)
	 throws DataException {
		  if (field instanceof FieldAutoId) return getSQLType((FieldAutoId)field);
		  if (field instanceof FieldBigInteger) return getSQLType((FieldBigInteger)field);
		  if (field instanceof FieldBigDecimal) return getSQLType((FieldBigDecimal)field);
		  if (field instanceof FieldBoolean) return getSQLType((FieldBoolean)field);
		  if (field instanceof FieldCharacter) return getSQLType((FieldCharacter)field);
		  if (field instanceof FieldColor) return getSQLType((FieldColor)field);
		  if (field instanceof FieldCurrency) return getSQLType((FieldCurrency)field);
		  if (field instanceof FieldDate) return getSQLType((FieldDate)field);
		  if (field instanceof FieldDateTime) return getSQLType((FieldDateTime)field);
		  if (field instanceof FieldDouble) return getSQLType((FieldDouble)field);
		  if (field instanceof FieldInteger) return getSQLType((FieldInteger)field);
		  if (field instanceof FieldLong) return getSQLType((FieldLong)field);
		  if (field instanceof FieldString) return getSQLType((FieldString)field);
		  if (field instanceof FieldTime) return getSQLType((FieldTime)field);
		  if (field instanceof FieldText) return getSQLType((FieldText)field);
		  if (field instanceof FieldBlob) return getSQLType((FieldBlob)field);
		  if (field instanceof FieldProperties) return getSQLType((FieldProperties)field);
		  if (field instanceof FieldImage) return getSQLType((FieldImage)field);
		  if (field instanceof FieldCombiner) return null;
		  throw new DataException("FIELD TYPE NOT FOUND " + field + " " +field.getClass());
	 }

	 abstract String getSQLType(FieldBigDecimal field);
	 abstract String getSQLType(FieldBigInteger field);
	 abstract String getSQLType(FieldBoolean field);
	 abstract String getSQLType(FieldCharacter field);
	 abstract String getSQLType(FieldColor field);
	 abstract String getSQLType(FieldCurrency field);
	 abstract String getSQLType(FieldDate field);
	 abstract String getSQLType(FieldDateTime field);
	 abstract String getSQLType(FieldDouble field);
	 abstract String getSQLType(FieldInteger field);
	 abstract String getSQLType(FieldLong field);
	 abstract String getSQLType(FieldAutoId field);
	 abstract String getSQLType(FieldString field);
	 abstract String getSQLType(FieldTime field);
	 abstract String getSQLType(FieldText field);
	 abstract String getSQLType(FieldBlob field);
	 abstract String getSQLType(FieldImage field);
	 abstract String getSQLType(FieldProperties field);

	 public String getSQLType(FieldStringSelect field) {
		  return getSQLType((FieldString) field);
	 }
	 public String getSQLType(FieldStringSequence field) {
		  return getSQLType((FieldString) field);
	 }
	 public String getSQLType(FieldThreadId field) {
		  return getSQLType((FieldBigInteger) field);
	 }
	 public String getSQLType(FieldUnique field) {
		  return getSQLType((FieldString) field);
	 }
	 public String getSQLType(FieldDateRange field) {
		  return getSQLType((FieldProperties) field);
	 }
	 public String getSQLType(FieldDateTimeRange field) {
		  return getSQLType((FieldProperties) field);
	 }
	 public String getSQLType(FieldPassword field) {
		  return getSQLType((FieldString) field);
	 }

	 public abstract void addField(DBConnection dbcon,Field field) throws SQLException;

	 public abstract void modifyTableField(DBConnection connection,Field field) throws SQLException;

	 public abstract void modifyTableField(DBConnection connection,String old_name,Field field) throws SQLException;

	 public abstract String getDropField(String name,String table);

	 /**
	  * Init the database server
	  * setup any initial properties that must be set for the database
	  */
	 public abstract void setupDatabaseServer(DBConnection connect) throws SQLException;

	 /**
	  * Creates the database
	  */
	 abstract boolean createDatabase(String path,String dbname,String username,String password);

	 public abstract void bulkLoadFile(DBConnection dbcon,String tablename,java.io.File file,String delimiter) throws SQLException;

	 public abstract void exportData(DBConnection dbcon,String select,java.io.File bulkfile) throws SQLException;

	 abstract void backupDB(DBConnection dbcon,java.io.File bakcupfile) throws Throwable;

	 abstract void restoreDB(DBConnection dbcon,java.io.File dbfile) throws Throwable;

}

